using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Ports;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace ShangHeng.HardwareSDK.CardReader
{
	internal class ZKUHFReader
	{
		public delegate void TagCallback(string strTag);

		private ushort POLYNOMIAL = 33800;

		private ushort PRESET_VALUE = ushort.MaxValue;

		private byte[] RecvBuff = new byte[8000];

		private byte[] SendBuff = new byte[300];

		private int RecvLength = 0;

		private SerialPort serialPort1;

		private TcpClient client;

		private Stream streamToTran;

		private int inventoryScanTime = 0;

		public TagCallback ReceiveCallback;

		private int mType = -1;

		public List<string> EPCIDs;

		public ZKUHFReader()
		{
			serialPort1 = new SerialPort();
		}

		private void GetCRC(byte[] pData, int ADataLen)
		{
			ushort current_crc_value = PRESET_VALUE;
			int i;
			for (i = 0; i <= ADataLen - 1; i++)
			{
				current_crc_value = (ushort)(current_crc_value ^ pData[i]);
				for (int j = 0; j < 8; j++)
				{
					current_crc_value = (((current_crc_value & 1) == 0) ? ((ushort)(current_crc_value >> 1)) : ((ushort)((current_crc_value >> 1) ^ POLYNOMIAL)));
				}
			}
			pData[i++] = (byte)(current_crc_value & 0xFFu);
			pData[i] = (byte)((uint)(current_crc_value >> 8) & 0xFFu);
		}

		private bool CheckCRC(byte[] pData, int len)
		{
			GetCRC(pData, len);
			if (pData[len + 1] == 0 && pData[len] == 0)
			{
				return true;
			}
			return false;
		}

		public byte[] HexStringToByteArray(string s)
		{
			s = s.Replace(" ", "");
			byte[] buffer = new byte[s.Length / 2];
			for (int i = 0; i < s.Length; i += 2)
			{
				buffer[i / 2] = Convert.ToByte(s.Substring(i, 2), 16);
			}
			return buffer;
		}

		public string ByteArrayToHexString(byte[] data)
		{
			StringBuilder sb = new StringBuilder(data.Length * 3);
			foreach (byte b in data)
			{
				sb.Append(Convert.ToString(b, 16).PadLeft(2, '0'));
			}
			return sb.ToString().ToUpper();
		}

		private int OpenNet(string ipAddr, int Port)
		{
			try
			{
				IPAddress ipAddress = IPAddress.Parse(ipAddr);
				client = new TcpClient();
				client.Connect(ipAddress, Port);
				streamToTran = client.GetStream();
				streamToTran.ReadTimeout = 1000;
				return 0;
			}
			catch (Exception ex)
			{
				ex.ToString();
				return 48;
			}
		}

		private int OpenCom(int Port, int Speed)
		{
			if (serialPort1.IsOpen)
			{
				serialPort1.Close();
			}
			try
			{
				serialPort1.PortName = "com" + Port;
				serialPort1.BaudRate = Speed;
				serialPort1.ReadTimeout = 200;
				serialPort1.Open();
				return 0;
			}
			catch (Exception ex)
			{
				ex.ToString();
				return 48;
			}
		}

		public int OpenComPort(int Port, ref byte ComAddr, int Speed)
		{
			if (OpenCom(Port, Speed) == 0)
			{
				mType = 0;
				byte addr = ComAddr;
				byte[] Verion = new byte[2];
				byte Model = 0;
				byte SupProtocol = 0;
				byte dmaxfre = 0;
				byte dminfre = 0;
				byte power = 0;
				byte ScanTime = 0;
				byte Ant = 0;
				byte BeepEn = 0;
				byte OutputRep = 0;
				byte CheckAnt = 0;
				int result = 48;
				if (GetReaderInformation(ref addr, Verion, ref Model, ref SupProtocol, ref dmaxfre, ref dminfre, ref power, ref ScanTime) == 0)
				{
					ComAddr = addr;
					return 0;
				}
				serialPort1.Close();
				return 48;
			}
			return 48;
		}

		public int CloseComPort()
		{
			if (serialPort1.IsOpen)
			{
				serialPort1.Close();
			}
			return 0;
		}

		public int OpenNetPort(string ipAddr, int Port, ref byte ComAddr)
		{
			if (OpenNet(ipAddr, Port) == 0)
			{
				mType = 1;
				byte addr = ComAddr;
				byte[] Verion = new byte[2];
				byte Model = 0;
				byte SupProtocol = 0;
				byte dmaxfre = 0;
				byte dminfre = 0;
				byte power = 0;
				byte ScanTime = 0;
				byte Ant = 0;
				byte BeepEn = 0;
				byte OutputRep = 0;
				byte CheckAnt = 0;
				if (GetReaderInformation(ref addr, Verion, ref Model, ref SupProtocol, ref dmaxfre, ref dminfre, ref power, ref ScanTime) == 0)
				{
					ComAddr = addr;
					return 0;
				}
				if (streamToTran != null)
				{
					streamToTran.Dispose();
				}
				if (client != null)
				{
					client.Close();
				}
				return 48;
			}
			return 48;
		}

		public int CloseNetPort()
		{
			try
			{
				if (streamToTran != null)
				{
					streamToTran.Dispose();
					streamToTran = null;
				}
				if (client != null)
				{
					client.Close();
					client = null;
				}
				return 0;
			}
			catch (Exception ex)
			{
				ex.ToString();
				return 48;
			}
		}

		private int SendDataToPort(byte[] dataToSend, int BytesOfSend)
		{
			RecvLength = 0;
			Array.Clear(RecvBuff, 0, 8000);
			try
			{
				if (mType == 0)
				{
					serialPort1.DiscardInBuffer();
					serialPort1.DiscardOutBuffer();
					serialPort1.Write(dataToSend, 0, BytesOfSend);
					return 0;
				}
				lock (streamToTran)
				{
					streamToTran.Flush();
					streamToTran.Write(dataToSend, 0, BytesOfSend);
					return 0;
				}
			}
			catch (Exception ex)
			{
				throw ex;
			}
		}

		private int GetDataFromPort(int cmd)
		{
			byte[] buffer = new byte[2560];
			int Count = 0;
			byte[] btArray = new byte[20000];
			int btLength = 0;
			long beginTime = Environment.TickCount;
			try
			{
				while (Environment.TickCount - beginTime < 2000)
				{
					Count = 0;
					Thread.Sleep(5);
					if (mType == 0)
					{
						int rlnum = serialPort1.BytesToRead;
						Count = serialPort1.Read(buffer, 0, rlnum);
					}
					else
					{
						Count = streamToTran.Read(buffer, 0, buffer.Length);
					}
					if (Count <= 0)
					{
						continue;
					}
					byte[] daw = new byte[Count + btLength];
					Array.Copy(btArray, 0, daw, 0, btLength);
					Array.Copy(buffer, 0, daw, btLength, Count);
					int index = 0;
					while (daw.Length - index > 4)
					{
						if (daw[index] >= 4 && daw[index + 2] == cmd)
						{
							int len = daw[index] & 0xFF;
							if (daw.Length < index + len + 1)
							{
								break;
							}
							byte[] epcArr = new byte[len + 1 + 2];
							Array.Copy(daw, index, epcArr, 0, epcArr.Length - 2);
							if (CheckCRC(epcArr, epcArr.Length - 2))
							{
								Array.Copy(epcArr, 0, RecvBuff, 0, epcArr.Length - 2);
								RecvLength = epcArr.Length - 2;
								return 0;
							}
							index++;
						}
						else
						{
							index++;
						}
					}
					if (daw.Length > index)
					{
						btLength = daw.Length - index;
						Array.Copy(daw, index, btArray, 0, btLength);
					}
					else
					{
						btLength = 0;
					}
				}
			}
			catch (Exception e)
			{
				e.ToString();
			}
			return 48;
		}

		public int GetReaderInformation(ref byte address, byte[] VersionInfo, ref byte ReaderType, ref byte TrType, ref byte dmaxfre, ref byte dminfre, ref byte powerdBm, ref byte ScanTime)
		{
			int result = 48;
			SendBuff[0] = 4;
			SendBuff[1] = address;
			SendBuff[2] = 33;
			GetCRC(SendBuff, 3);
			SendDataToPort(SendBuff, 5);
			result = GetDataFromPort(33);
			if (result == 0)
			{
				if (RecvBuff[2] == 33)
				{
					if (RecvBuff[3] == 0)
					{
						address = RecvBuff[1];
						Array.Copy(RecvBuff, 4, VersionInfo, 0, 2);
						ReaderType = RecvBuff[6];
						TrType = RecvBuff[7];
						dmaxfre = RecvBuff[8];
						dminfre = RecvBuff[9];
						powerdBm = RecvBuff[10];
						ScanTime = RecvBuff[11];
						inventoryScanTime = RecvBuff[11] * 100;
					}
					return RecvBuff[3];
				}
				return 238;
			}
			return result;
		}

		public int ReadCard_G2(ref byte ConAddr, byte[] EPC, byte Mem, byte WordPtr, byte Num, byte[] Password, byte maskadr, byte maskLen, byte maskFlag, byte[] Data, byte EPClength, ref int errorcode)
		{
			int result = 48;
			if (maskFlag == 1)
			{
				SendBuff[0] = (byte)(EPClength + 14);
				SendBuff[1] = ConAddr;
				SendBuff[2] = 2;
				SendBuff[3] = (byte)((int)EPClength / 2);
				Array.Copy(EPC, 0, SendBuff, 4, EPClength);
				SendBuff[EPClength + 4] = Mem;
				SendBuff[EPClength + 5] = WordPtr;
				SendBuff[EPClength + 6] = Num;
				Array.Copy(Password, 0, SendBuff, EPClength + 7, 4);
				SendBuff[EPClength + 11] = maskadr;
				SendBuff[EPClength + 12] = maskLen;
			}
			else
			{
				SendBuff[0] = (byte)(EPClength + 12);
				SendBuff[1] = ConAddr;
				SendBuff[2] = 2;
				SendBuff[3] = (byte)((int)EPClength / 2);
				Array.Copy(EPC, 0, SendBuff, 4, EPClength);
				SendBuff[EPClength + 4] = Mem;
				SendBuff[EPClength + 5] = WordPtr;
				SendBuff[EPClength + 6] = Num;
				Array.Copy(Password, 0, SendBuff, EPClength + 7, 4);
			}
			GetCRC(SendBuff, SendBuff[0] - 1);
			SendDataToPort(SendBuff, SendBuff[0] + 1);
			result = GetDataFromPort(2);
			if (result == 0)
			{
				if (RecvBuff[3] == 0)
				{
					Array.Copy(RecvBuff, 4, Data, 0, Num * 2);
					errorcode = 0;
				}
				else if (RecvBuff[3] == 252)
				{
					errorcode = RecvBuff[4];
				}
				return RecvBuff[3];
			}
			return result;
		}

		public int WriteCard_G2(ref byte ConAddr, byte[] EPC, byte Mem, byte WordPtr, byte Writedatalen, byte[] Writedata, byte[] Password, byte maskadr, byte maskLen, byte maskFlag, int WrittenDataNum, byte EPClength, ref int errorcode)
		{
			int result = 48;
			if (maskFlag == 1)
			{
				SendBuff[0] = (byte)(EPClength + Writedatalen + 14);
				SendBuff[1] = ConAddr;
				SendBuff[2] = 3;
				SendBuff[3] = (byte)((int)Writedatalen / 2);
				SendBuff[4] = (byte)((int)EPClength / 2);
				Array.Copy(EPC, 0, SendBuff, 5, EPClength);
				SendBuff[EPClength + 5] = Mem;
				SendBuff[EPClength + 6] = WordPtr;
				Array.Copy(Writedata, 0, SendBuff, EPClength + 7, Writedatalen);
				Array.Copy(Password, 0, SendBuff, EPClength + Writedatalen + 7, 4);
				SendBuff[EPClength + Writedatalen + 11] = maskadr;
				SendBuff[EPClength + Writedatalen + 12] = maskLen;
			}
			else
			{
				SendBuff[0] = (byte)(EPClength + Writedatalen + 14);
				SendBuff[1] = ConAddr;
				SendBuff[2] = 3;
				SendBuff[3] = (byte)((int)Writedatalen / 2);
				SendBuff[4] = (byte)((int)EPClength / 2);
				Array.Copy(EPC, 0, SendBuff, 5, EPClength);
				SendBuff[EPClength + 5] = Mem;
				SendBuff[EPClength + 6] = WordPtr;
				Array.Copy(Writedata, 0, SendBuff, EPClength + 7, Writedatalen);
				Array.Copy(Password, 0, SendBuff, EPClength + Writedatalen + 7, 4);
			}
			GetCRC(SendBuff, SendBuff[0] - 1);
			SendDataToPort(SendBuff, SendBuff[0] + 1);
			result = GetDataFromPort(3);
			if (result == 0)
			{
				if (RecvBuff[3] == 0)
				{
					errorcode = 0;
				}
				else if (RecvBuff[3] == 252)
				{
					errorcode = RecvBuff[4];
				}
				return RecvBuff[3];
			}
			return result;
		}

		public int Writedfre(ref byte ConAddr, ref byte dmaxfre, ref byte dminfre)
		{
			int result = 48;
			SendBuff[0] = 6;
			SendBuff[1] = ConAddr;
			SendBuff[2] = 34;
			SendBuff[3] = dmaxfre;
			SendBuff[4] = dminfre;
			GetCRC(SendBuff, 5);
			SendDataToPort(SendBuff, 7);
			result = GetDataFromPort(34);
			if (result == 0)
			{
				return RecvBuff[3];
			}
			return result;
		}

		public int WriteComAdr(ref byte ConAddr, byte ComAdrData)
		{
			int result = 48;
			SendBuff[0] = 5;
			SendBuff[1] = ConAddr;
			SendBuff[2] = 36;
			SendBuff[3] = ComAdrData;
			GetCRC(SendBuff, 4);
			SendDataToPort(SendBuff, 6);
			result = GetDataFromPort(36);
			if (result == 0)
			{
				return RecvBuff[3];
			}
			return result;
		}

		public int WriteScanTime(ref byte ConAddr, byte ScanTime)
		{
			int result = 48;
			SendBuff[0] = 5;
			SendBuff[1] = ConAddr;
			SendBuff[2] = 37;
			SendBuff[3] = ScanTime;
			GetCRC(SendBuff, 4);
			SendDataToPort(SendBuff, 6);
			result = GetDataFromPort(37);
			if (result == 0)
			{
				return RecvBuff[3];
			}
			return result;
		}

		public int Writebaud(ref byte ConAddr, byte baud)
		{
			int result = 48;
			SendBuff[0] = 5;
			SendBuff[1] = ConAddr;
			SendBuff[2] = 40;
			SendBuff[3] = baud;
			GetCRC(SendBuff, 4);
			SendDataToPort(SendBuff, 6);
			result = GetDataFromPort(40);
			if (result == 0)
			{
				return RecvBuff[3];
			}
			return result;
		}

		public int SetPowerDbm(ref byte ConAddr, byte PowerDbm)
		{
			int result = 48;
			SendBuff[0] = 5;
			SendBuff[1] = ConAddr;
			SendBuff[2] = 47;
			SendBuff[3] = PowerDbm;
			GetCRC(SendBuff, 4);
			SendDataToPort(SendBuff, 6);
			result = GetDataFromPort(47);
			if (result == 0)
			{
				return RecvBuff[3];
			}
			return result;
		}

		public int SetWorkMode(ref byte ConAddr, byte[] Parameter)
		{
			int result = 48;
			SendBuff[0] = 10;
			SendBuff[1] = ConAddr;
			SendBuff[2] = 53;
			Array.Copy(Parameter, 0, SendBuff, 3, 6);
			GetCRC(SendBuff, 9);
			SendDataToPort(SendBuff, 11);
			result = GetDataFromPort(53);
			if (result == 0)
			{
				return RecvBuff[3];
			}
			return result;
		}

		private int GetInventoryData()
		{
			EPCIDs = new List<string>();
			byte[] buffer = new byte[256];
			int Count = 0;
			byte[] daw = new byte[8000];
			int btLength = 0;
			int index = 0;
			long beginTime = Environment.TickCount;
			try
			{
				while (Environment.TickCount - beginTime < inventoryScanTime + 1000)
				{
					Count = 0;
					Thread.Sleep(5);
					if (mType == 0)
					{
						int rlnum = serialPort1.BytesToRead;
						Count = serialPort1.Read(buffer, 0, rlnum);
					}
					else
					{
						Count = streamToTran.Read(buffer, 0, buffer.Length);
					}
					if (Count <= 0)
					{
						continue;
					}
					Array.Copy(buffer, 0, daw, btLength, Count);
					btLength += Count;
					while (btLength - index > 4)
					{
						if (daw[index] >= 4 && daw[index + 2] == 1)
						{
							int len = daw[index] & 0xFF;
							if (btLength < index + len + 1)
							{
								break;
							}
							byte[] epcArr = new byte[len + 1 + 2];
							Array.Copy(daw, index, epcArr, 0, epcArr.Length - 2);
							if (CheckCRC(epcArr, epcArr.Length - 2))
							{
								Array.Copy(epcArr, 0, RecvBuff, RecvLength, epcArr.Length - 2);
								RecvLength += epcArr.Length - 2;
								if (RecvBuff[index + 3] == 3 || RecvBuff[index + 3] == 4 || RecvBuff[index + 3] == 1 || RecvBuff[index + 3] == 2)
								{
									int btlen = RecvBuff[index] - 6;
									int p = 0;
									while (btlen > p)
									{
										int epclen = RecvBuff[index + 5 + p];
										byte[] btarr = new byte[epclen];
										Array.Copy(RecvBuff, index + 6 + p, btarr, 0, epclen);
										p += epclen + 1;
										string epchex = ByteArrayToHexString(btarr);
										EPCIDs.Add(epchex);
										if (ReceiveCallback != null)
										{
											ReceiveCallback(epchex);
										}
									}
								}
								if (RecvBuff[index + 3] != 3 && RecvBuff[index + 3] != 4)
								{
									return 0;
								}
								index += epcArr.Length - 2;
							}
							else
							{
								index++;
							}
						}
						else
						{
							index++;
						}
					}
				}
			}
			catch (Exception e)
			{
				throw e;
			}
			return 48;
		}

		public int Inventory_G2(ref byte ConAddr, byte AdrTID, byte LenTID, byte TIDFlag)
		{
			int result = 48;
			if (TIDFlag == 1)
			{
				SendBuff[0] = 6;
				SendBuff[1] = ConAddr;
				SendBuff[2] = 1;
				SendBuff[3] = AdrTID;
				SendBuff[4] = LenTID;
			}
			else
			{
				SendBuff[0] = 4;
				SendBuff[1] = ConAddr;
				SendBuff[2] = 1;
			}
			GetCRC(SendBuff, SendBuff[0] - 1);
			SendDataToPort(SendBuff, SendBuff[0] + 1);
			return GetInventoryData();
		}
	}
}
